package fun.flyee.android.pengshan.api;

import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import fun.flyee.android.pengshan.Constant;
import fun.flyee.android.pengshan.Storage;
import fun.flyee.android.pengshan.acts.Result;
import fun.flyee.android.pengshan.events.UnauthEvent;
import fun.flyee.android.pengshan.utils.Logger;
import fun.flyee.android.pengshan.utils.Sha1;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class ApiClient {

    private final static String TAG = "API";

    public static final MediaType JSON_TYPE = MediaType.get("application/json; charset=utf-8");

    public static void post(String path, JSON params, OnResponse onResponse) {
        RequestBody requestBody = RequestBody.create(params.toString(), JSON_TYPE);
        Request.Builder builder1 = new Request.Builder().url(Constant.apiUrl() + path).post(requestBody);
        String token = Storage.get(Storage.TOKEN);
        if (!TextUtils.isEmpty(token)) {
            builder1.addHeader("Authentication", "Bearer " + token);
        }
        builder1.addHeader("Request-From", "app");
        Request request = builder1.build();
        execute(request, onResponse);
    }

    public static void get(String path, JSONObject params, OnResponse onResponse) {
        String url = Constant.apiUrl() + path;
        if (params != null && params.size() > 0) {
            url += "?";
            Iterator<Map.Entry<String, Object>> it = params.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry entry = it.next();
                url += entry.getKey().toString() + "=" + entry.getValue().toString() + "&";
            }
            url = url.substring(0, url.length() - 1);
        }
        Request.Builder builder = new Request.Builder().url(url);
        String token = Storage.get(Storage.TOKEN);
        if (!TextUtils.isEmpty(token)) {
            builder.addHeader("Authentication", "Bearer " + token);
        }
        builder.addHeader("Request-From", "app");
        Request request = builder.build();
        execute(request, onResponse);
    }

    private static void execute(Request request, OnResponse onResponse) {
        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Logger.e(TAG, e);
                    onResponse.onResult(Result.genErr(e.getMessage()));
                }

                @Override
                public void onResponse(Call call, Response response) {
                    Logger.d(TAG, "Request: " + request.url().toString());
                    Logger.d(TAG, response.protocol() + " " + response.code() + " " + response.message());
                    if (response.code() == 401) {
                        EventBus.getDefault().post(new UnauthEvent());
                        return;
                    }
                    try {
                        if (request.url().toString().contains("online")
                                && !TextUtils.isEmpty(response.header("Authentication"))) {
                            Storage.set(Storage.TOKEN, response.header("Authentication"));
                        }
                        String text = response.body().string();
                        Logger.d(TAG, "Response: " + text);
                        Result result = JSONObject.parseObject(text, Result.class);
                        onResponse.onResult(result);
                    } catch (IOException ie) {
                        onResponse.onResult(Result.genErr("读取数据错误"));
                    } catch (JSONException je) {
                        onResponse.onResult(Result.genErr("数据解析错误"));
                    }
                }
            });
        } catch (Exception e) {
            Logger.e("network error", e);
            onResponse.onResult(Result.genErr(e.getMessage()));
        }
    }

    public static void upload(File file, OnResponse onResponse) {
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);
        builder.addFormDataPart("file", file.getName(),
                RequestBody.create(MediaType.parse("multipart/form-data"), file));
        RequestBody requestBody = builder.build();
        Request request = new Request.Builder()
                .url(Constant.apiUrl() + "/api-file/files-anon")
                .addHeader("Authorization", Storage.get(Storage.TOKEN))
                .post(requestBody)
                .build();
        execute(request, onResponse);
    }

    public static void download(String url, File file, OnProgress onProgress, OnResponse onResponse) {
        Request.Builder builder = new Request.Builder().url(Constant.apiUrl() + url);
        String token = Storage.get(Storage.TOKEN);
        if (!TextUtils.isEmpty(token)) {
            builder.addHeader("Authentication", token);
        }
        Request request = builder.build();
        OkHttpClient client = new OkHttpClient();
        client.newCall(request).enqueue(new Callback() {

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                if (response != null) {
                    if (response.code() != 200) {
                        onResponse.onResult(Result.genErr("下载失败-" + response.code()));
                        return;
                    }
                    ResponseBody body = response.body();
                    long total = body.contentLength();
                    if (total < 10485760l) {
                        onResponse.onResult(Result.genErr("下载失败-异常"));
                        return;
                    }
                    InputStream is = body.byteStream();
                    FileOutputStream fos = null;
                    try {
                        fos = new FileOutputStream(file);
                        int len = 0;
                        int done = 0;
                        int preProgress = 0;
                        byte[] buffer = new byte[2048];
                        while (-1 != (len = is.read(buffer))) {
                            fos.write(buffer, 0, len);
                            done += len;
                            int currProgress = done * 100 / (int) total;
                            if (currProgress - preProgress > 0) {
                                preProgress = currProgress;
                                onProgress.onProgress(currProgress);
                            }
                        }
                        fos.flush();
                        onResponse.onResult(Result.genSuccess());
                    } catch (IOException e) {
                        onResponse.onResult(Result.genErr("下载失败-IO"));
                    } finally {
                        try {
                            if (fos != null) {
                                fos.close();
                            }
                            if (is != null) {
                                is.close();
                            }
                        } catch (IOException e) {

                        }
                    }
                }
            }

            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                onResponse.onResult(Result.genErr("下载失败"));
            }
        });
    }

    public static void checkVersion(OnResponse onResponse) {
        get("/back-stage/app/version/new", new JSONObject(), onResponse);
    }

    public static void getDictByCode(String code,OnResponse onResp){
        JSONObject json = new JSONObject();
        json.put("code", code);
        get("/upms/sys/dict/findDictByCode", json, onResp);
    }

    public static void log(String userName, String status, String desc){
        JSONObject json = new JSONObject();
        json.put("userName", userName);
        json.put("status", status);
        json.put("describe", desc);
        ApiClient.post("/back-stage/log/insert", json, (resp) -> {
        });
    }

    public interface OnResponse {
        void onResult(Result result);
    }

    public interface OnProgress {
        void onProgress(int progress);
    }

}
